package com.webplasm.render.tags.u;

import java.util.Arrays;
import java.util.List;

import com.webplasm.context.RenderContext;
import com.webplasm.render.engine.RenderException;
import com.webplasm.render.tags.TagInterface;
import com.webplasm.render.tags.WrappedNode;
import com.webplasm.store.VariableStoreInterface;
import com.webplasm.store.VariableContainer.VariableType;

public class Function extends WrappedNode implements TagInterface {
	private static final String DESCRIPTION = "Performs string manipulation functionality.";

	public String getNamespace() {
		return "u";
	}
	
	public List<String> getAttributes() {
		return Arrays.asList("var", "function", "search", "replace");
	}
	
	public List<String> getManagedNodes() {
		return null;
	}

	public String getDescription() {
		return DESCRIPTION;
	}

	@Override
	public StringBuffer render(RenderContext rContext) throws RenderException {
		if (elements.get("function") == null) {
			throw new RenderException("u:function requires a function to be set.");
		}
		
		if (elements.get("function").equalsIgnoreCase("search")) {
			String var = elements.get("var");
			String searchFor = getWrappedAttribute(rContext, "search");
			String searchContents = super.render(rContext).toString();
			boolean foundBoolean = searchContents.contains(searchFor);
			
			if (var != null) {
				VariableStoreInterface vsInterface = rContext.getVariableStore().getVariable(elements.get("var"), VariableType.BOOLEAN);

				vsInterface.setValue(Boolean.valueOf(foundBoolean));
			} else {
				return new StringBuffer(Boolean.toString(foundBoolean));
			}
		} else if (elements.get("function").equalsIgnoreCase("lower") || elements.get("function").equalsIgnoreCase("lcase")) {
			String var = elements.get("var");
			String bodyContents = super.render(rContext).toString().toLowerCase();
			
			if (var != null) {
				VariableStoreInterface vsInterface = rContext.getVariableStore().getVariable(elements.get("var"), VariableType.STRING);

				vsInterface.setValue(bodyContents);
			} else {
				return new StringBuffer(bodyContents);
			}
		} else if (elements.get("function").equalsIgnoreCase("upper") || elements.get("function").equalsIgnoreCase("ucase")) {
			String var = elements.get("var");
			String bodyContents = super.render(rContext).toString().toUpperCase();
			
			if (var != null) {
				VariableStoreInterface vsInterface = rContext.getVariableStore().getVariable(elements.get("var"), VariableType.STRING);

				vsInterface.setValue(bodyContents);
			} else {
				return new StringBuffer(bodyContents);
			}
		} else if (elements.get("function").equalsIgnoreCase("length")) {
			String var = elements.get("var");
			int bodyContents = super.render(rContext).toString().length();
			
			if (var != null) {
				VariableStoreInterface vsInterface = rContext.getVariableStore().getVariable(elements.get("var"), VariableType.INTEGER);

				vsInterface.setValue(Integer.valueOf(bodyContents));
			} else {
				return new StringBuffer(Integer.toString(bodyContents));
			}
		} else if (elements.get("function").equalsIgnoreCase("trim")) {
			String var = elements.get("var");
			String bodyContents = super.render(rContext).toString().trim();
			
			if (var != null) {
				VariableStoreInterface vsInterface = rContext.getVariableStore().getVariable(elements.get("var"), VariableType.STRING);

				vsInterface.setValue(bodyContents);
			} else {
				return new StringBuffer(bodyContents);
			}
		} else if (elements.get("function").equalsIgnoreCase("left")) {
			if (elements.get("range") == null) {
				throw new RenderException("u:function 'left' function requires a range.");
			}
			
			String var = elements.get("var");
			int range = Integer.parseInt(getWrappedAttribute(rContext, "range"));
			String bodyContents = super.render(rContext).toString();
			
			if (range > bodyContents.length()) {
				throw new RenderException("u:function 'left' range (" + range + ") exceeds string length (" +
						bodyContents.length() + ").");
			}
			
			bodyContents = bodyContents.substring(0, range);
			
			if (var != null) {
				VariableStoreInterface vsInterface = rContext.getVariableStore().getVariable(elements.get("var"), VariableType.STRING);

				vsInterface.setValue(bodyContents);
			} else {
				return new StringBuffer(bodyContents);
			}
		} else if (elements.get("function").equalsIgnoreCase("right") || elements.get("function").equalsIgnoreCase("rtrim")) {
			if (elements.get("range") == null) {
				throw new RenderException("u:function 'right' function requires a range.");
			}
			
			String var = elements.get("var");
			int range = Integer.parseInt(getWrappedAttribute(rContext, "range"));
			String bodyContents = super.render(rContext).toString();
			
			if (elements.get("function").equalsIgnoreCase("rtrim")) {
				bodyContents = bodyContents.trim();
			}
			
			if (range > bodyContents.length()) {
				throw new RenderException("u:function 'right' range (" + range + ") exceeds string length (" +
						bodyContents.length() + ").");
			}
			
			bodyContents = bodyContents.substring(bodyContents.length() - range);
			
			if (var != null) {
				VariableStoreInterface vsInterface = rContext.getVariableStore().getVariable(elements.get("var"), VariableType.STRING);

				vsInterface.setValue(bodyContents);
			} else {
				return new StringBuffer(bodyContents);
			}
		} else if (elements.get("function").equalsIgnoreCase("initcap")) {
			String var = elements.get("var");
			String bodyContents = super.render(rContext).toString();
			boolean capitalize = true;
			char[] data = bodyContents.toCharArray();
			
			for (int i = 0; i < data.length; i++) {
				if (data[i] == ' ' || Character.isWhitespace(data[i])) {
					capitalize = true;
				} else if (capitalize) {
					data[i] = Character.toUpperCase (data[i]);
					capitalize = false;
				} else {
					data[i] = Character.toLowerCase (data[i]);
				}
			}
			
			bodyContents = new String (data);

			if (var != null) {
				VariableStoreInterface vsInterface = rContext.getVariableStore().getVariable(elements.get("var"), VariableType.STRING);

				vsInterface.setValue(bodyContents);
			} else {
				return new StringBuffer(bodyContents);
			}
		} else if (elements.get("function").equalsIgnoreCase("truncate")) {
			if (elements.get("range") == null) {
				throw new RenderException("u:function 'truncate' function requires a range.");
			}
			
			String var = elements.get("var");
			int range = Integer.parseInt(getWrappedAttribute(rContext, "range"));
			String bodyContents = super.render(rContext).toString();
			
			if (range <= bodyContents.length()) {
				bodyContents = bodyContents.substring(0, range) + " ...";
			}
			
			if (var != null) {
				VariableStoreInterface vsInterface = rContext.getVariableStore().getVariable(elements.get("var"), VariableType.STRING);

				vsInterface.setValue(bodyContents);
			} else {
				return new StringBuffer(bodyContents);
			}
		} else if (elements.get("function").equalsIgnoreCase("repeat")) {
			if (elements.get("repeat") == null) {
				throw new RenderException("u:function 'repeat' function requires a repeat value.");
			}
			
			String var = elements.get("var");
			int repeat = Integer.parseInt(getWrappedAttribute(rContext, "repeat"));
			String bodyContents = super.render(rContext).toString();
			StringBuffer bodyRepeat = new StringBuffer();
			
			for(int i = 0; i < repeat; i++) {
				bodyRepeat.append(bodyContents);
			}
			
			bodyContents = bodyRepeat.toString();
			
			if (var != null) {
				VariableStoreInterface vsInterface = rContext.getVariableStore().getVariable(elements.get("var"), VariableType.STRING);

				vsInterface.setValue(bodyContents);
			} else {
				return new StringBuffer(bodyContents);
			}
		} else if (elements.get("function").equalsIgnoreCase("substring")) {
			if (elements.get("start") == null && elements.get("end") == null) {
				throw new RenderException("u:function 'substring' function requires a start or end value.");
			}
			
			String var = elements.get("var");
			String bodyContents = super.render(rContext).toString();
			int start = 0;
			
			if (elements.get("start") != null) {
				start = Integer.parseInt(getWrappedAttribute(rContext, "start"));
			}
			
			int end = bodyContents.length();
			
			if (elements.get("end") != null) {
				end = Integer.parseInt(getWrappedAttribute(rContext, "end"));
			}
			
			if (end > bodyContents.length()) {
				throw new RenderException("u:function 'substring' end value exceeds string length.");
			}
			
			if (start > bodyContents.length()) {
				throw new RenderException("u:function 'substring' start value exceeds string length.");
			}
			
			bodyContents = bodyContents.substring(start, end);
			
			if (var != null) {
				VariableStoreInterface vsInterface = rContext.getVariableStore().getVariable(elements.get("var"), VariableType.STRING);

				vsInterface.setValue(bodyContents);
			} else {
				return new StringBuffer(bodyContents);
			}
		} else if (elements.get("function").equalsIgnoreCase("endswith")) {
			String var = elements.get("var");
			String endsWith = getWrappedAttribute(rContext, "search");
			String searchContents = super.render(rContext).toString();
			boolean foundBoolean = searchContents.endsWith(endsWith);
			
			if (var != null) {
				VariableStoreInterface vsInterface = rContext.getVariableStore().getVariable(elements.get("var"), VariableType.BOOLEAN);

				vsInterface.setValue(Boolean.valueOf(foundBoolean));
			} else {
				return new StringBuffer(Boolean.toString(foundBoolean));
			}
		} else if (elements.get("function").equalsIgnoreCase("startswith")) {
			String var = elements.get("var");
			String startsWith = getWrappedAttribute(rContext, "search");
			String searchContents = super.render(rContext).toString();
			boolean foundBoolean = searchContents.startsWith(startsWith);
			
			if (var != null) {
				VariableStoreInterface vsInterface = rContext.getVariableStore().getVariable(elements.get("var"), VariableType.BOOLEAN);

				vsInterface.setValue(Boolean.valueOf(foundBoolean));
			} else {
				return new StringBuffer(Boolean.toString(foundBoolean));
			}
		} else if (elements.get("function").equalsIgnoreCase("indexof")) {
			String var = elements.get("var");
			String matches = getWrappedAttribute(rContext, "search");
			String searchContents = super.render(rContext).toString();
			int foundIndex = searchContents.indexOf(matches);
			
			if (var != null) {
				VariableStoreInterface vsInterface = rContext.getVariableStore().getVariable(elements.get("var"), VariableType.INTEGER);

				vsInterface.setValue(Integer.valueOf(foundIndex));
			} else {
				return new StringBuffer(Integer.toString(foundIndex));
			}
		} else if (elements.get("function").equalsIgnoreCase("lastindexof")) {
			String var = elements.get("var");
			String matches = getWrappedAttribute(rContext, "search");
			String searchContents = super.render(rContext).toString();
			int foundIndex = searchContents.lastIndexOf(matches);
			
			if (var != null) {
				VariableStoreInterface vsInterface = rContext.getVariableStore().getVariable(elements.get("var"), VariableType.INTEGER);

				vsInterface.setValue(Integer.valueOf(foundIndex));
			} else {
				return new StringBuffer(Integer.toString(foundIndex));
			}
		} else if (elements.get("function").equalsIgnoreCase("replace")) {
			if (elements.get("search") == null) {
				throw new RenderException("u:function requires a search phrase when function is replace.");
			}
			
			if (elements.get("replace") == null) {
				throw new RenderException("u:function requires a replace phrase when function is replace.");
			}
			
			String var = elements.get("var");
			String search = getWrappedAttribute(rContext, "search");
			String replace = getWrappedAttribute(rContext, "replace");
			String replaceContents = super.render(rContext).toString();
			
			replaceContents = replaceContents.replaceAll(search, replace);
			
			if (var != null) {
				VariableStoreInterface vsInterface = rContext.getVariableStore().getVariable(elements.get("var"), VariableType.STRING);

				vsInterface.setValue(replaceContents);
			} else {
				return new StringBuffer(replaceContents);
			}
		}
		
		return new StringBuffer();
	}
}